home *** CD-ROM | disk | FTP | other *** search
- /*
- C* preprocessor -- utility routines.
-
- Source: utl.c
- Started: October 7, 1985
- Version:
- February 20, 1987
- March 7, 1989
-
- PUBLIC DOMAIN SOFTWARE
-
- The CSTAR program was placed in the public domain on June 15, 1991,
- by its author and sole owner,
-
- Edward K. Ream
- 1617 Monroe Street
- Madison, WI 53711
- (608) 257-0802
-
- CSTAR may be used for any commercial or non-commercial purpose.
-
- See cstar.h or cstar.c for a DISCLAIMER OF WARRANTIES.
- */
- #include "cstar.h"
-
- /*
- Externally visible routines:
- */
- int char_val (register char *s);
- void conv2s (int a, char *s);
- void convl2s (long a, char *s);
- void conul2sc (unsigned long n, char *s, int c);
- void conl2h (unsigned long n, char *s, int c);
- void fatal (char * message);
- void revcpy (char *s1, char *s2);
- void scan_number (int base);
- void skip_bl (void);
- bool skip_crlf (void);
- void skip_1line (void);
- void skip_past (void);
- void skip_pp (void);
- void skip_ws (void);
- void t_error (char * message);
- void t_2error (char * mess1, char *mess2);
- void t_3serr (struct node *p, char * mess1, char *mess2, char *mess3);
- void t_warning (char * message);
- void t_2warning (char * mess1, char *mess2);
- void t_help (char * message);
- void t_2help (char * mess1, char *mess2);
- void g_error (struct node * p, char * message);
- void g_help (struct node *p, char * message);
- unsigned int str_val (unsigned char *d);
-
- /*
- Internal routines:
- */
- static bool is_base_digit (int base);
-
- /*
- Return the value of a character constant.
- */
- int
- char_val(register char *s)
- {
- int val;
-
- TRACEPB("char_val", printf("(%s)\n", s));
-
- if (*s != '\\') {
- RETURN_INT("char_val", (int) *s);
- }
- s++;
- switch (*s) {
- case 'b': RETURN_INT("char_val", '\b');
- case 'f': RETURN_INT("char_val", '\f');
- case 'n': RETURN_INT("char_val", '\n');
- case 'r': RETURN_INT("char_val", '\r');
- case 't': RETURN_INT("char_val", '\t');
- case '\'': RETURN_INT("char_val", '\'');
- case '\\': RETURN_INT("char_val", '\\');
-
- default:
- if (*s < '0' || *s > '7') {
- RETURN_INT("char_val", (int)*s);
- }
- val = 0;
- while (*s >= '0' && *s <= '7') {
- val = val * 8 + (int)*s - '0';
- s++;
- }
- RETURN_INT("char_val", val);
- }
- }
-
- /*
- Convert a signed integer n to a string s[].
- The length of s must be large enough to hold the result.
- */
- void
- conv2s(int a, register char *s)
- {
- register char *d, *ss;
- register int sn;
- register unsigned long n;
- char temp [INT_DIGITS];
-
- SL_DISABLE();
-
- /* Do the sign and handle 0x8000 correctly */
- if (a >= 0) {
- sn = 0;
- /* these casts ARE NOT redundant: DO NOT fix them! */
- /* see note in lint.doc about unsigned extending casts */
- n = (unsigned long) (long) a;
- }
- else {
- sn = 1;
- n = (unsigned long) (long) (-a);
- }
-
- /* put digits in reverse order into temp */
- d = &temp[0];
- *d++ = 0;
- if (n) while (n) {
- /* NOTE: in assembly, we would divide once */
- *d++ = (char)(n % 10) + '0';
- n = n / 10;
- }
- else {
- *d++ = '0';
- }
-
- /* insert the sign */
- if (sn) {
- *d++ = '-';
- }
-
- /* Reverse temp into s. */
- ss = s;
-
- /* -----
- while(*ss++ = *--d) {};
- ----- */
-
- do {
- *ss++ = *--d;
- }
- while (*d);
-
-
- TRACEP("conv2s", printf("converts %d to <%s>\n", a, s));
- }
-
- /*
- Convert a long n to a string s[].
- The length of s must be large enough to hold the result.
- */
- void
- convl2s(long a, register char *s)
- {
- register char *d, *ss;
- register int sn;
- register unsigned long n;
- char temp [LONG_DIGITS];
-
- SL_DISABLE();
-
- /* Do the sign and handle 0x80000000 correctly */
- if (a >= 0) {
- sn = 0;
- n = (unsigned long) a;
- }
- else {
- sn = 1;
- n = (unsigned long) (-a);
- }
-
- /* put digits in reverse order into temp */
- d = &temp[0];
- *d++ = 0;
- if (n) while (n) {
- /* NOTE: in assembly, we would divide once */
- *d++ = (char)(n % 10) + '0';
- n = n / 10;
- }
- else {
- *d++ = '0';
- }
-
- /* insert the sign */
- if (sn) {
- *d++ = '-';
- }
-
- /* Reverse temp into s. */
- ss = s;
-
- /* -----
- while(*ss++ = *--d) {};
- ----- */
-
- do {
- *ss++ = *--d;
- }
- while (*d);
-
- TRACEP("convl2s", printf("converts %ld to <%s>\n", a, s));
- }
-
- /*
- Convert a long n to a string s[], minimum digit count c.
- The length of s must be large enough to hold any result.
- */
- void
- conul2sc(register unsigned long n, register char *s, register int c)
- {
- register char *d, *ss;
- char temp [LONG_DIGITS];
-
- SL_DISABLE();
-
- /* put digits in reverse order into temp */
- d = &temp[0];
- *d++ = 0;
- while (n) {
- /* NOTE: in assembly, we would divide once */
- *d++ = (char)(n % 10) + '0';
- n /= 10;
- if (c > 0) {
- c--;
- }
- }
- while (c > 0) {
- c--;
- *d++ = '0';
- }
-
- /* Reverse temp into s. */
- ss = s;
-
- /* -----
- while(*ss++ = *--d) {};
- ----- */
-
- do {
- *ss++ = *--d;
- }
- while (*d);
-
- TRACEP("conul2sc", printf("converts %lu, count %d to <%s>\n", n, c, s));
- }
-
- /*
- Convert a long n to a hex string s[], minimum digit count c.
- The length of s must be large enough to hold any result.
- */
- void
- conl2h(register unsigned long n, register char *s, register int c)
- {
- register char *d, *ss;
- char temp [LONG_DIGITS];
-
- SL_DISABLE();
-
- /* put digits in reverse order into temp */
- d = &temp[0];
- *d++ = 0;
- while (n) {
- *d = ((char)n & 15) + '0';
- if (*d > '9') {
- *d += 7;
- }
- d++;
- n >>= 4;
- if (c > 0) {
- c--;
- }
- }
- while (c > 0) {
- c--;
- *d++ = '0';
- }
-
- /* Reverse temp into s. */
- ss = s;
-
- /* -----
- while(*ss++ = *--d) {};
- ----- */
-
- do {
- *ss++ = *--d;
- }
- while (*d);
-
- TRACEP("conl2h", printf("converts %lu, count %d to <%s>\n", n, c, s));
- }
-
- /*
- Give an error message and exit.
- */
- void
- fatal(char * message)
- {
- SL_DISABLE();
-
- printf("fatal error: ");
- t_error(message);
- sysabort();
-
- }
-
- /*
- Return true if the global ch is a digit in the indicated base.
-
- Return the value of the digit in digit_val;
- */
- static unsigned char digit_val;
-
- static bool
- is_base_digit(register int base)
- {
- TRACEPB("is_base_digit", printf("(%d)\n", base));
-
- if (ch >= '0' && ch <= '9') {
- digit_val = ch - '0';
- RETURN_BOOL("is_base_digit", TRUE);
- }
- else if (base != 16) {
- RETURN_BOOL("is_base_digit", FALSE);
- }
- else if (ch >= 'a' && ch <= 'f') {
- digit_val = ch - 'a' + 10;
- RETURN_BOOL("is_base_digit", TRUE);
- }
- else {
- digit_val = ch - 'A' + 10;
- RETURN_BOOL("is_base_digit", ch >= 'A' && ch <= 'F');
- }
- }
-
- /*
- Copy string s2 to string s1 in reverse order.
- */
- void
- revcpy(char *s1, char *s2)
- {
- int length;
-
- SL_DISABLE();
-
- length = str_len(s2);
- s2 = s2 + length - 1;
-
- for (; length; length--) {
- *s1++ = *s2--;
- }
- *s1 = '\0';
-
- TRACEP("revcpy", printf("revcpy copy returns s1 = <%s>\n", s1));
- }
-
- /*
- Get value of a string of digits into t_value.
- Continue until a non base digit is found.
- */
- void
- scan_number(register int base)
- {
- SL_DISABLE();
-
- t_value = 0;
- while (is_base_digit(base)) {
- t_value = ((long)base * t_value) + (long)digit_val;
- sysnext();
- }
-
- TRACEP("scan_number",
- printf("scan_number sets t_value: %ld\n", t_value));
- }
-
- /*
- Skip blanks and tabs, but not newlines.
- */
- void
- skip_bl(void)
- {
- STAT("skip_bl");
-
- while (ch == ' ' || ch == '\t') {
- sysnext();
- }
- }
-
- /*
- Skip a newline, optionally preceeded or followed by '\r'.
- Return TRUE if seen.
- */
- bool
- skip_crlf(void)
- {
- STAT("skip_crlf");
-
- if (ch == '\r') {
- sysnext();
- if (ch == '\n') {
- sysnext();
- return TRUE;
- }
- else {
- return FALSE;
- }
- }
- else if (ch == '\n') {
- sysnext();
- if (ch == '\r') {
- sysnext();
- }
- return TRUE;
- }
- else {
- return FALSE;
- }
- }
-
- /*
- Skip characters up to but NOT including a newline.
- */
- void
- skip_1line(void)
- {
- STAT("skip_1line");
-
- while (ch != END_FILE && ch != '\n') {
- sysnext();
- }
- }
-
- /*
- Skip characters up to and including a newline.
- */
- void
- skip_past(void)
- {
- STAT("skip_past");
-
- while (ch != END_FILE && ch != '\n') {
- sysnext();
- }
-
- if (ch == '\n') {
- sysnext();
- do_nl();
- }
- }
-
- /*
- Skip to the end of the current preprocessor directive.
- Do NOT skip past the final newline.
-
- Note that directives may contain comments (!!) and may be continued
- from line to line.
- */
- void
- skip_pp(void)
- {
- STAT("skip_pp");
-
- for (;;) {
- skip_ws();
- if (ch == '\\') {
- sysnext();
- if (!skip_crlf()) {
- /* Skip the escaped character. */
- sysnext();
- }
- }
- else if (ch == END_FILE || ch == '\n') {
- return;
- }
- else {
- sysnext();
- }
- }
- }
-
- /*
- Skip blanks, tabs and comments.
- */
- void
- skip_ws(void)
- {
- STAT("skip_ws");
-
- for(;;) {
-
- switch(ch) {
-
- case ' ':
- case '\t':
- sysnext();
- continue;
-
- case '/':
- sysnext();
- if (ch == '*') {
- sysnext();
- t_comment();
- continue;
- }
- else {
- syspush(ch);
- ch = '/';
- return;
- }
-
- default:
- return;
- }
- }
- }
-
- /*
- Process a non-fatal error messages.
- */
- void
- t_error(char * message)
- {
- SL_DISABLE();
-
- (void) syscsts();
- t_errcount++;
- printf("line %3d, %s: %s\n", t_line, t_file, message);
- }
-
- void
- t_2error(char * mess1, char *mess2)
- {
- SL_DISABLE();
-
- (void) syscsts();
- t_errcount++;
- printf("line %3d, %s: %s%s\n", t_line, t_file, mess1, mess2);
- }
-
- void
- t_3serr(struct node *p, char * mess1, char *mess2, char *mess3)
- {
- SL_DISABLE();
-
- t_errcount++;
- (void) syscsts();
- printf("line %3d, %s: %s%s%s", t_line, t_file, mess1, mess2, mess3);
- if (p) {
- printf(" (see line %d)\n", p -> n_linno);
- }
- else {
- printf("\n");
- }
- }
-
- /*
- Process a warning message.
- */
- void
- t_warning(char * message)
- {
- SL_DISABLE();
- printf("line %3d, %s (warning): %s\n", t_line, t_file, message);
- }
-
- void
- t_2warning(char * mess1, char *mess2)
- {
- SL_DISABLE();
- printf("line %3d, %s (warning): %s%s\n", t_line, t_file, mess1, mess2);
- }
-
- /*
- Process a less-important warning message.
- */
- void
- t_help(char * message)
- {
- SL_DISABLE();
- printf("line %3d, %s (note): %s\n", t_line, t_file, message);
- }
-
- void
- t_2help(char * mess1, char *mess2)
- {
- SL_DISABLE();
- printf("line %3d, %s (note): %s%s\n", t_line, t_file, mess1, mess2);
- }
-
- /*
- Code generation errors
- */
- void
- g_error(struct node * p, char * message)
- {
- SL_DISABLE();
- if (p != NULL) {
- printf("g_error/line %d file %s: %s\n",
- p -> n_linno, "??", message);
- }
- else {
- printf("g_error/line ?? file ??: %s\n", message);
- }
- }
-
- /*
- Process a less-important warning message.
- */
- void
- g_help(struct node *p, char * message)
- {
- SL_DISABLE();
- if (p != NULL) {
- printf("g_help/line %3d file %s (note): %s\n",
- p -> n_linno, "??", message);
- }
- else {
- printf("g_help/line ?? file ??: %s\n", message);
- }
- }
-
- /*
- Re-evaluate a string constant; this may shorten it
-
- Return its length; it may contain imbedded zeroes once processed
-
- CAUTION: if the string is transformed, it is always shortened. Callers
- of this routine may count on that fact.
- */
- unsigned int
- str_val(register unsigned char *d)
- {
- register unsigned char val, *dd, *s;
-
- TRACEPB("str_val", printf("(%s)\n", d));
-
- /* outer loop to scan the string */
- s = dd = d;
- while (*s) {
- if (*s != '\\') {
- *d++ = *s++;
- continue;
- }
- ++s;
- switch (*s) {
- case 'b': *d++ = '\b'; ++s; break;
- case 'f': *d++ = '\f'; ++s; break;
- case 'n': *d++ = '\n'; ++s; break;
- case 'r': *d++ = '\r'; ++s; break;
- case 't': *d++ = '\t'; ++s; break;
- case '\'': *d++ = '\''; ++s; break;
- case '\\': *d++ = '\\'; ++s; break;
-
- default:
- if (*s < '0' || *s > '7') {
- continue;
- }
- val = 0;
- while (*s >= '0' && *s <= '7') {
- val = val * 8 + *s - '0';
- s++;
- }
- *d++ = val;
- }
- }
- *d++ = '\0';
-
- RETURN_UINT("str_val", (unsigned int)(d - dd));
- }
-